<?php

namespace CrontabConsole\drivers;

use Yii;
use yii\helpers\BaseFileHelper;
use yii\base\BaseObject;
use Mmarica\DisplayTable;


/**
 * 任务文件存储
 */
class Mysql extends BaseObject implements DriverInterface {

    private $db;
    public $dsn;
    public $username;
    public $password;
    public $charset = 'utf8';
    public $tablePrefix = '';

    // 表名
    private $tableName = 'console_crontab';

    public function __construct($config = []) {
        parent::__construct($config);
    }

    /**
     * 初始化任务
     */
    public function init()
    {
        parent::init();
        $this->installCrontab();
    }

    /**
     * 初始化任务
     */
    public function installCrontab() 
    {

        // 创建目录
        BaseFileHelper::createDirectory(Yii::getAlias('@runtime/crontab'));

        $this->db = new \yii\db\Connection([
            'dsn' => $this->dsn,
            'username' => $this->username,
            'password' => $this->password,
            'charset' => $this->charset,
            'tablePrefix' => $this->tableName
        ]);

        $createTableSql = $this->db->getQueryBuilder()->createTable($this->tableName, [
            'id' => 'pk',
            'route' => "string not null comment '任务路由'",
            'count' => "int(11) comment '任务运行累积次数'",
            'crontab_str' => "string not null comment 'crontab解析符'",
            'switch' => "tinyint(1) comment '开关: 0-close 1-open'",
            'status' => "tinyint(1) comment '任务状态: 0-正常 1-运行中 2-运行出错'",
            'last_rundate' => "datetime comment '上次任务运行时间'",
            'next_rundate' => "datetime comment '下次任务运行时间'",
            'exectime' => "decimal(9,2) comment '任务单次运行时长(秒)'",
        ]);

        $createTableSql = str_replace('CREATE TABLE', 'CREATE TABLE If Not Exists', $createTableSql);
        
        // 创建定时任务表
        $this->db->createCommand($createTableSql)->execute();
    }

    /**
     * 获取所有任务
     */
    public function getAllTasks() 
    {
        return $this->db->createCommand("SELECT * FROM {$this->tableName}")->queryAll();
    }

    /**
     * 获取达到指定时间的任务
     * @return array $tasks [Task, Task....]
     */
    public function getRunTasks()
    {
        $nowdatetime = date('Y-m-d H:i');
        $datas = $this->db->createCommand("SELECT * FROM {$this->tableName} WHERE `switch` = 1 and `status` in(0,2) and `next_rundate` <= '$nowdatetime'")
            ->queryAll();
        $runTasks = [];

        foreach ($datas as $t) {
            $t['class'] = '\CrontabConsole\Task';
            $task = Yii::createObject($t);
            $runTasks[$task->id] = $task;
        }

        return $runTasks;
    }

    public function add(\CrontabConsole\Task $task) 
    {
        $sql = "SELECT * FROM {$this->tableName} ";
        $where = 'WHERE';

        $task->calcNextRunDatetime();
        $arrTask = $task->toArray();

        // 修改任务
        if ($task->id) {
            $where .= (' `id` = ' . $task->id);
            $one = $this->db->createCommand($sql . $where)->queryOne();
            if (empty($one)) {
                throw new Exception("失败, 任务ID不存在 => id={$task->id}");
            }
            $arrTask = array_filter($arrTask);
            $updated = array_merge($one, $arrTask);
            $res = $this->db->createCommand()->update($this->tableName, $updated, ['id' => $task->id])->execute();
        } else { // 新增任务
            unset($arrTask['id']);
            $res = $this->db->createCommand()->insert($this->tableName, $arrTask)->execute();
        }

        return $res;
    }

    public function del($id) 
    {
        return $this->db->createCommand()->delete($this->tableName, ['id' => intval($id)])->execute();
    }
    
    public function updateOne(\CrontabConsole\Task $task)
    {
        if ($task->status == 1) {
            $where = "id = {$task->id} and `status` = 0";
        } else {
            $where = "id = {$task->id}";
        }
        return $this->db->createCommand()->update($this->tableName, $task->toArray(), $where)->execute();
    }

    /**
     * 控制台打印任务状态
     */
    public function display() 
    {
        $tasks = $this->getAllTasks();

        $dataRows = [];

        $statusTextMap = [
            0 => '--',
            1 => 'RUNNING',
            2 => 'ERROR',
        ];

        foreach($tasks as $t) {

            $d = [
                $t['id'],
                $t['route'],
                $t['crontab_str'],
                $t['last_rundate'],
                $t['next_rundate'],
                $statusTextMap[$t['status']],
                $t['count'],
                $t['exectime'],
            ];

            $dataRows[] = $d;
        }

        echo DisplayTable::create()
            ->headerRow(['id', 'route', 'crontab_str', 'last_rundate', 'next_rundate', 'status', 'exec_count', 'exec_time(s)'])
            ->dataRows($dataRows)
            ->toText()
            ->roundedBorder()
            ->generate();
    }

    
    public function refresh() 
    {

    }
    
}